﻿using System.ComponentModel.Composition.Extensions;
using System.ComponentModel.Composition.Hosting;
using System.Globalization;
using System.Windows.Markup;
using System.Reflection;
using System.Windows;
using System.Deployment.Application;
using System;
using System.IO;
using System.IO.IsolatedStorage;


namespace ScrumFactory.Windows {
    

    public partial class App : Application {

        private ViewModel.ShellViewModel shellViewModel;
        private ApplicationInstanceMonitor<string> instanceMonitor;

        public CompositionContainer Container { get; private set; }

        
        public App() {
            this.instanceMonitor = new ApplicationInstanceMonitor<string>();
            this.DispatcherUnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(App_DispatcherUnhandledException);
            this.Startup += new StartupEventHandler(AppStartup);
            this.Exit += new ExitEventHandler(App_Exit);
        }

        void App_Exit(object sender, ExitEventArgs e) {
            if (shellViewModel != null)
                shellViewModel.SaveRecentProjects();
        }

        void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {
            
            // if has no shell yet throws it anyway
            if (shellViewModel == null)
                return;

            // tries to get it as a Scrum factory exceptions
            ScrumFactory.Exceptions.ScrumFactoryException sfEx = null;
            if (e.Exception is ScrumFactory.Exceptions.ScrumFactoryException)
                sfEx = e.Exception as ScrumFactory.Exceptions.ScrumFactoryException;
            if (e.Exception.InnerException is ScrumFactory.Exceptions.ScrumFactoryException)
                sfEx = e.Exception.InnerException as ScrumFactory.Exceptions.ScrumFactoryException;

            if (e.Exception is System.Net.Http.HttpRequestException)
                sfEx = new Exceptions.NetworkException();
           


            // if is not a factoy exception, throws it to the OS
            if (sfEx==null) {
                LogError(e.Exception);
                return;
            }

            // if is a ScrumFactoryExcpetion let the shell handle it            
            shellViewModel.HandleScrumFactoryException(sfEx);
            e.Handled = true;
        }


        private void AppStartup(object sender, StartupEventArgs e) {
            
            if (!instanceMonitor.Assert()) {
                
                // Defer to another instance.
                instanceMonitor.NotifyNewInstance(GetQueryString());
                this.Shutdown();
                return;
            }

            instanceMonitor.NewInstanceCreated += OnNewInstanceCreated;

            SetFrameworkElementToUserCulture();

            var catalog = new AggregateCatalog();


            string deployPath = Assembly.GetExecutingAssembly().Location.Replace("ScrumFactory.Windows.exe", "");

            catalog.Catalogs.Add(new DirectoryCatalog(deployPath, "ScrumFactory.*.dll"));
            catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));

            string pluginPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments) + "\\Scrum Factory\\Plugins";
            if (System.IO.Directory.Exists(pluginPath))
                catalog.Catalogs.Add(new DirectoryCatalog(pluginPath, "*.dll"));

            catalog.Catalogs.Add(new ConfigurationCatalog());

            Container = new CompositionContainer(catalog);
                        
            this.shellViewModel = Container.GetExport<ViewModel.ShellViewModel>().Value;

            // starts all view models with the StartsWithApp interface
            Container.GetExportedValues<ScrumFactory.Composition.ViewModel.IStartsWithApp>();

            var args = System.Web.HttpUtility.ParseQueryString(GetQueryString());        
            this.shellViewModel.Show(args);

            

        }

        private void OnNewInstanceCreated(object sender, NewInstanceCreatedEventArgs<string> e) {
            var args = System.Web.HttpUtility.ParseQueryString(e.Message);

            this.shellViewModel.Show(args);

            
        }

        public string GetQueryString() {
            if (!ApplicationDeployment.IsNetworkDeployed || ApplicationDeployment.CurrentDeployment.ActivationUri == null) {
                string[] args = Environment.GetCommandLineArgs();                
                if (args.Length > 1)
                    return args[1];
                else
                    return string.Empty;                
            }
            return
                ApplicationDeployment.CurrentDeployment.ActivationUri.Query;
                
        }

        /// <summary>
        /// Sets the Culture to the current user culture.
        /// </summary>        
        private void SetFrameworkElementToUserCulture() {

            FrameworkElement.LanguageProperty.OverrideMetadata(
                typeof(FrameworkElement),
                new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentUICulture.IetfLanguageTag)));

        }

        public Thickness SystemBorderThickness {
            get {
                double taskBarHeight = SystemParameters.VirtualScreenHeight - SystemParameters.WorkArea.Height + System.Windows.SystemParameters.ResizeFrameHorizontalBorderHeight;                
                return new Thickness(
                    SystemParameters.ResizeFrameVerticalBorderWidth -2,
                    SystemParameters.ResizeFrameHorizontalBorderHeight -1,
                    SystemParameters.ResizeFrameVerticalBorderWidth -3,
                    taskBarHeight -2);
            }
        }


        private void LogError(Exception ex) {

            IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User|IsolatedStorageScope.Assembly|IsolatedStorageScope.Domain, null, null);

            IsolatedStorageFileStream oStream = new IsolatedStorageFileStream("factoryErrorLog.txt", FileMode.Append, FileAccess.Write, isoStore);

            StreamWriter writer = new StreamWriter(oStream);
            writer.WriteLine(DateTime.Now);
            writer.WriteLine(ex.Message);

            if (ex is System.Reflection.TargetInvocationException && ex.InnerException != null) {
                writer.WriteLine("INNER: " + ex.InnerException.Message);
                writer.WriteLine(ex.InnerException.StackTrace.ToString());
            }
            else
                writer.WriteLine(ex.StackTrace.ToString());

            writer.WriteLine("------------------------------------------------------------------------------");
            writer.Close();

        }


      
    }


}
